﻿using IdentityManagement;
using PermissionManagement;
using System;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Security.Claims;
using Volo.Abp.Users;
using Xms.Abp.Domain.Repositories;

namespace AccountManagement;

public class XmsPermissionChecker : IPermissionChecker, ITransientDependency
{
    public IAbpLazyServiceProvider LazyServiceProvider { get; set; }
    protected ICurrentPrincipalAccessor PrincipalAccessor
        => LazyInject<ICurrentPrincipalAccessor>();
    protected IXmsRepository<PermissionGrant, Guid> Repository
        => LazyInject<IXmsRepository<PermissionGrant, Guid>>();
    protected IIdentityUserRepository UserRepository
        => LazyInject<IIdentityUserRepository>();
    protected ICurrentUser CurrentUser
        => LazyInject<ICurrentUser>();

    protected TService LazyInject<TService>()
    {
        return LazyServiceProvider.LazyGetRequiredService<TService>();
    }

    public async Task<bool> IsGrantedAsync(string name)
    {
        return await IsGrantedAsync(PrincipalAccessor.Principal, name);
    }

    public async Task<bool> IsGrantedAsync(ClaimsPrincipal claimsPrincipal, string name)
    {
        Check.NotNull(name, nameof(name));

        if (name.IsNullOrWhiteSpace())
        {
            return true;
        }
        if (!CurrentUser.IsAuthenticated)
        {
            return false;
        }
        var user = await UserRepository.FindAsync(CurrentUser.Id.Value);
        if (user == null)
        {
            return false;
        }

        if (user.UserName == "admin")
        {
            return true;
        }

        var index = name.LastIndexOf(".");
        var moduleName = name[..index];
        var functionName = name[(index + 1)..];

        var roleId = CurrentUser.Roles[0];

        var isGranted = await (await Repository.AsNoTrackingAsync()).AnyAsync(r => roleId == r.ProviderKey && r.ProviderName == "R" && r.ModuleName == moduleName && r.FunctionName == functionName);

        return isGranted;
    }

    public async Task<MultiplePermissionGrantResult> IsGrantedAsync(string[] names)
    {
        return await IsGrantedAsync(PrincipalAccessor.Principal, names);
    }

    public async Task<MultiplePermissionGrantResult> IsGrantedAsync(ClaimsPrincipal claimsPrincipal, string[] names)
    {
        Check.NotNull(names, nameof(names));

        var result = new MultiplePermissionGrantResult();
        if (!names.Any())
        {
            return result;
        }
        if (!CurrentUser.IsAuthenticated)
        {
            return result;
        }
        var user = await UserRepository.FindAsync(CurrentUser.Id.Value);
        if (user == null)
        {
            return result;
        }

        if (user.UserName == "admin")
        {
            return result;
        }

        var permissions = names
            .Select(r =>
            {
                var index = r.LastIndexOf(".");
                var moduleName = r[..index];
                var functionName = r[(index + 1)..];
                return new { MoudleName = moduleName, FunctionName = functionName };
            })
            .GroupBy(r => r.MoudleName)
            .ToDictionary(r => r.Key, r => r.Select(s => s.FunctionName));

        var roleId = CurrentUser.Roles[0];
        var dict = (await (await Repository.AsNoTrackingAsync()).Where(r => r.ProviderName == "R" && r.ProviderKey == roleId && permissions.Keys.Contains(r.ModuleName)).GroupBy(r => r.ModuleName).Select(r => new
        {
            r.Key,
            Items = r.Select(s => s.FunctionName)
        }).ToListAsync()).ToDictionary(r => r.Key, r => r.Items.ToList());

        foreach (var moduleName in permissions.Keys)
        {
            var functionNames = permissions[moduleName];
            foreach (var functionName in functionNames)
            {
                result.Result[moduleName + "." + functionName] = dict.ContainsKey(moduleName) && dict[moduleName].Contains(functionName) ? PermissionGrantResult.Granted : PermissionGrantResult.Prohibited;
            }
        }

        return result;
    }
}
